/*
 * Copyright 2017 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.sample.helper;

import android.annotation.TargetApi;
import android.app.NativeActivity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.opengl.GLUtils;
import android.os.Build;
import android.util.Log;

import java.io.File;
import java.io.FileInputStream;

import javax.microedition.khronos.opengles.GL10;

@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public class NDKHelper {

  private static final String TAG = "NDKHelper";

  public NDKHelper(NativeActivity act) {
    activity = act;
  }

  public void loadLibrary(String soname) {
    if (!soname.isEmpty()) {
      System.loadLibrary(soname);
      loadedSO = true;
    }
  }

  public static Boolean checkSOLoaded() {
    if (!loadedSO) {
      Log.e("NDKHelper",
              "--------------------------------------------\n"
                      + ".so has not been loaded. To use JUI helper, please initialize with \n"
                      + "NDKHelper::Init( ANativeActivity* activity, const char* helper_class_name, const char* native_soname);\n"
                      + "--------------------------------------------\n");
      return false;
    } else
      return true;
  }

  private static boolean loadedSO = false;
  NativeActivity activity;

  //
  // Load Bitmap
  // Java helper is useful decoding PNG, TIFF etc rather than linking libPng
  // etc separately
  //
  private int nextPOT(int i) {
    int pot = 1;
    while (pot < i)
      pot <<= 1;
    return pot;
  }

  private Bitmap scaleBitmap(Bitmap bitmapToScale, float newWidth,
                             float newHeight) {
    if (bitmapToScale == null)
      return null;
    // get the original width and height
    int width = bitmapToScale.getWidth();
    int height = bitmapToScale.getHeight();
    // create a matrix for the manipulation
    Matrix matrix = new Matrix();

    // resize the bit map
    matrix.postScale(newWidth / width, newHeight / height);

    // recreate the new Bitmap and set it back
    return Bitmap.createBitmap(bitmapToScale, 0, 0,
            bitmapToScale.getWidth(), bitmapToScale.getHeight(), matrix,
            true);
  }

  public class TextureInformation {
    boolean ret;
    boolean alphaChannel;
    int originalWidth;
    int originalHeight;
  }

  public Object loadTexture(String path) {
    Bitmap bitmap = null;
    TextureInformation info = new TextureInformation();
    try {
      String str = path;
      if (!path.startsWith("/")) {
        str = "/" + path;
      }

      File file = new File(activity.getExternalFilesDir(null), str);
      if (file.canRead()) {
        bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
      } else {
        bitmap = BitmapFactory.decodeStream(activity.getResources()
                .getAssets().open(path));
      }
      // Matrix matrix = new Matrix();
      // // resize the bit map
      // matrix.postScale(-1F, 1F);
      //
      // // recreate the new Bitmap and set it back
      // bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
      // bitmap.getHeight(), matrix, true);

    } catch (Exception e) {
      Log.w("NDKHelper", "Coundn't load a file:" + path);
      info.ret = false;
      return info;
    }

    if (bitmap != null) {
      GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
    }
    info.ret = true;
    info.alphaChannel = bitmap.hasAlpha();
    info.originalWidth = getBitmapWidth(bitmap);
    info.originalHeight = getBitmapHeight(bitmap);

    return info;

  }

  public Bitmap openBitmap(String path, boolean iScalePOT) {
    Bitmap bitmap = null;
    try {
      bitmap = BitmapFactory.decodeStream(activity.getResources()
              .getAssets().open(path));
      if (iScalePOT) {
        int originalWidth = getBitmapWidth(bitmap);
        int originalHeight = getBitmapHeight(bitmap);
        int width = nextPOT(originalWidth);
        int height = nextPOT(originalHeight);
        if (originalWidth != width || originalHeight != height) {
          // Scale it
          bitmap = scaleBitmap(bitmap, width, height);
        }
      }

    } catch (Exception e) {
      Log.w("NDKHelper", "Coundn't load a file:" + path);
    }

    return bitmap;
  }

  public int getBitmapWidth(Bitmap bmp) {
    return bmp.getWidth();
  }

  public int getBitmapHeight(Bitmap bmp) {
    return bmp.getHeight();
  }

  public void getBitmapPixels(Bitmap bmp, int[] pixels) {
    int w = bmp.getWidth();
    int h = bmp.getHeight();
    bmp.getPixels(pixels, 0, w, 0, 0, w, h);
  }

  public void closeBitmap(Bitmap bmp) {
    bmp.recycle();
  }

  public String getNativeLibraryDirectory(Context appContext) {
    ApplicationInfo ai = activity.getApplicationInfo();

    Log.w("NDKHelper", "ai.nativeLibraryDir:" + ai.nativeLibraryDir);

    if ((ai.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0
            || (ai.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
      return ai.nativeLibraryDir;
    }
    return "/system/lib/";
  }

  public String getApplicationName() {
    final PackageManager pm = activity.getPackageManager();
    ApplicationInfo ai;
    try {
      ai = pm.getApplicationInfo(activity.getPackageName(), 0);
    } catch (final NameNotFoundException e) {
      ai = null;
    }
    String applicationName = (String) (ai != null ? pm
            .getApplicationLabel(ai) : "(unknown)");
    return applicationName;
  }

  public String getStringResource(String resourceName) {
    int id = activity.getResources().getIdentifier(resourceName, "string", activity.getPackageName());
    String value = id == 0 ? "" : (String) activity.getResources().getText(id);
    return value;
  }

  //
  // Audio related helpers
  //
  @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
  public int getNativeAudioBufferSize() {
    int SDK_INT = android.os.Build.VERSION.SDK_INT;
    if (SDK_INT >= 17) {
      AudioManager am = (AudioManager) activity
              .getSystemService(Context.AUDIO_SERVICE);
      if (am != null) {
        String framesPerBuffer = am
                .getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
        return Integer.parseInt(framesPerBuffer);
      } else {
        Log.e(TAG, "Cannot get Audio Service!");
      }
    }
    return 0;
  }

  public int getNativeAudioSampleRate() {
    return AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_SYSTEM);
  }

  /*
   * Helper to execute function in UIThread
   */
  public void runOnUIThread(final long p) {
    if (checkSOLoaded()) {
      activity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
          RunOnUiThreadHandler(p);
        }
      });
    }
  }

  /*
   * Native code helper for RunOnUiThread
   */
  native public void RunOnUiThreadHandler(long pointer);
}
